package com.guonl.open.api.config;


import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.TypeReference;
import feign.RequestInterceptor;
import feign.RequestTemplate;
import org.apache.commons.codec.binary.Hex;
import org.apache.commons.codec.digest.DigestUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.CollectionUtils;

import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.*;
import java.util.stream.Collectors;

public class OpenApiInterceptor implements RequestInterceptor {

    protected final Logger logger = LoggerFactory.getLogger(getClass());

    private OpenApiProperties openApiProperties;

    public OpenApiInterceptor(OpenApiProperties wlhyOpenApiProperties) {
        this.openApiProperties = wlhyOpenApiProperties;
    }

    @Override
    public void apply(RequestTemplate requestTemplate) {
        Collection<String> headers = requestTemplate.headers().get("api-key");
        if (CollectionUtils.isEmpty(headers)) {
            throw new IllegalArgumentException("api-key参数未传递");
        }
        String apiKey = headers.stream().findFirst().get();

        List<OpenApiProperties.ApiKeyInfo> apiKeyInfoList = openApiProperties.getApiKeyList();
        Optional<OpenApiProperties.ApiKeyInfo> keyInfoOptional = apiKeyInfoList
            .stream()
            .filter(apiKeyInfo -> apiKeyInfo.getApiKey().equals(apiKey))
            .findFirst();

        if (!keyInfoOptional.isPresent()) {
            throw new IllegalArgumentException("api-key未配置");
        }

        OpenApiProperties.ApiKeyInfo apiKeyInfo = keyInfoOptional.get();
        String apiSecret = apiKeyInfo.getApiSecret();

        String timestamp = System.currentTimeMillis() + "";
        String method = requestTemplate.method();
        String host = requestTemplate.feignTarget().url();

        String uri = requestTemplate.url();
        String url = host + uri;
        String requestUrl = "";
        try {
            requestUrl = new URI(url).getPath();
        } catch (URISyntaxException e) {
            throw new RuntimeException(e);
        }

        SortedMap<String, Object> allParams = getAllParams(requestTemplate);
        String queryjsonStr = JSON.toJSONString(allParams);
        String sign = generateSign(apiSecret, method, requestUrl, queryjsonStr, timestamp);

        //设置header
        requestTemplate.header("KEY", apiKey);
        requestTemplate.header("SIGN", sign);
        requestTemplate.header("Timestamp", timestamp);

    }

    private SortedMap<String, Object> getAllParams(RequestTemplate requestTemplate) {
        //请求参数集合
        SortedMap<String, Object> allParams = new TreeMap<>();

        //处理RequestParam
        Map<String, Collection<String>> queries = requestTemplate.queries();
        queries.forEach((key, value) -> {
            allParams.put(key, value.stream().collect(Collectors.joining(",")));
        });

        //处理请求body
        if (null != requestTemplate.body()) {
            int length = requestTemplate.body().length;
            if (0 < length) {
                String body = requestTemplate.requestBody().asString();
                if (StringUtils.isNotBlank(body)) {
                    Map<String, Object> map = JSON.parseObject(body, new TypeReference<Map<String, Object>>() {
                    });
                    allParams.putAll(map);
                }
            }
        }
        return allParams;
    }

    private String generateSign(String apiSecret, String methodName, String uri, String queryjsonStr, String timestamp) {
        String signatureString = String.format("%s\n%s\n%s\n%s", methodName, uri, DigestUtils.sha512Hex(queryjsonStr), timestamp);

        String signature = "";
        try {
            Mac hmacSha512 = Mac.getInstance("HmacSHA512");
            SecretKeySpec spec = new SecretKeySpec(apiSecret.getBytes(), "HmacSHA512");
            hmacSha512.init(spec);
            signature = Hex.encodeHexString(hmacSha512.doFinal(signatureString.getBytes()));
        } catch (Exception e) {
            logger.error("生成签名失败", e);
            throw new RuntimeException("生成签名失败");
        }
        return signature;
    }


}
